package com.example.demo003argsresolver.config;

import com.example.demo003argsresolver.domain.CurrUserVo;
import com.example.demo003argsresolver.service.TokenService;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;

/**
 * 自定义参数解析器**CurrUserArgumentResolver**并完成注册
 */
public class CurrUserArgumentResolver implements HandlerMethodArgumentResolver {

    @Autowired
    TokenService tokenService;
    // 只有标注有CurrUser注解，并且数据类型是CurrUserVo/Map/Object的才给与处理
    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        boolean b = parameter.hasParameterAnnotation(CurrUser.class);
        Class<?> type = parameter.getParameterType();
        return b && (CurrUser.class.isAssignableFrom(type) || Map.class.isAssignableFrom(type) || Object.class.isAssignableFrom(type));
    }

    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
        // 从请求头中拿到 token，然后根据 token 获取当前登录用户
        String token = request.getHeader("Authorization");
        CurrUserVo currUserVo = tokenService.getUserByToken(token);
        if(currUserVo == null){
            return null;
        }
        // 判断参数类型进行返回
        Class<?> parameterType = parameter.getParameterType();
        if (Map.class.isAssignableFrom(parameterType)){
            String str = new ObjectMapper().writeValueAsString(currUserVo);
            Map map = new ObjectMapper().readValue(str, Map.class);
            BeanUtils.copyProperties(currUserVo, map);
            return map;
        }else {
            return currUserVo;
        }
    }
}
